package com.ziytek.web.citizen.service;

import com.google.gson.Gson;
import com.ziytek.web.citizen.constant.NumConstant;
import com.ziytek.web.citizen.constant.ServerConstant;
import com.ziytek.web.citizen.mapper.BoardConfigMapper;
import com.ziytek.web.citizen.mapper.OperationDetailMapper;
import com.ziytek.web.citizen.model.bean.CommandBoardInfo;
import com.ziytek.web.citizen.model.bean.CommandBoardOutInfo;
import com.ziytek.web.citizen.model.bean.CommandIssuedSuccess;
import com.ziytek.web.citizen.model.bean.CommandOutInfo;
import com.ziytek.web.citizen.pojo.basic.BoardConfig;
import com.ziytek.web.citizen.pojo.basic.DoorConfig;
import com.ziytek.web.citizen.pojo.basic.OperationDetail;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author fenghx
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class CommandBoardInfoService {

    private final Gson gson;
    private final DoorsService doorsService;
    private final BoardConfigMapper boardConfigMapper;
    private final OperationDetailMapper operationDetailMapper;


    public List<CommandOutInfo> getCommandOutInfo(CommandIssuedSuccess command, boolean firstCommand) {
        var commandBoardOutInfos = getCommandBoardOutInfo(command, firstCommand);
        if (commandBoardOutInfos.isEmpty()) {
            return Collections.emptyList();
        }

        List<CommandOutInfo> commandOutInfos = new ArrayList<>();
        for (var c : commandBoardOutInfos) {
            var commandOutInfo = getCommandOutInfo(c);
            commandOutInfos.add(commandOutInfo);
        }

        return commandOutInfos;
    }

    public List<CommandBoardOutInfo> getCommandBoardOutInfo(CommandIssuedSuccess command, boolean firstCommand) {
        var commandBoardInfos = getCommandBoardInfo(command, firstCommand);
        if (commandBoardInfos.isEmpty()) {
            return Collections.emptyList();
        }
        //log.info("获取的commandBoardInfos：{}", gson.toJson(commandBoardInfos));

        Map<String, CommandBoardOutInfo> doorMap = new HashMap<>();
        long start = System.currentTimeMillis();
        var th = Thread.startVirtualThread(() -> {
            for (var c : commandBoardInfos) {
                // 相同的通道号，找恒流板编号LIST
                var key = "" + c.getStepId() + c.getOrderNo() + c.getSingleChannel() + gson.toJson(c.getCells());
                var co = doorMap.get(key);
                if (co == null) {
                    co = new CommandBoardOutInfo();
                }

                co.setStepId(c.getStepId());
                co.setSingleChannel(c.getSingleChannel());

                var boardAddress = co.getBoardAddress();
                if (boardAddress == null) {
                    boardAddress = new ArrayList<>();
                }

                boardAddress.add(c.getBoardAddress());
                co.setBoardAddress(boardAddress);
                co.setCells(c.getCells());
                doorMap.put(key, co);
            }
        });
        try {
            th.join();
        } catch (InterruptedException e) {
            log.error("getCommandBoardOutInfo thread interrupted", e);
        }

        log.info("获取的getCommandBoardOutInfo time:{}ms", System.currentTimeMillis() - start);
        return doorMap.values().stream().toList();
    }

    public List<CommandBoardInfo> getCommandBoardInfo(CommandIssuedSuccess command, boolean firstCommand) {
        Assert.notNull(command, "command is null");

        // 单个通道
        if (command.isSingleChannel()) {
            return getSingleCommandBoardInfo(command, firstCommand);
        }

        // 全局指令下发
        // 查询配置，不同版本对应机柜门机通道总数(一个机柜门对应4个恒流板，一个板子对应8个通道，总共32个通道)
        List<DoorConfig> doors = doorsService.getDoorsConfig();
        Assert.notEmpty(doors, "CommandIssuedSuccess doors is empty");

        var cabinetNo = command.getReqCabinetNo();

        // 查询所有板子地址
        List<CommandBoardInfo> commandBoardInfos = new ArrayList<>();
        var nowTime = System.currentTimeMillis();

        long startTime = System.currentTimeMillis();
        var boardConfigLists = boardConfigMapper.queryAllListByDoor(doors.stream().map(DoorConfig::getDoor).toList());
        List<Integer> addressNumList = null;
        if (!CollectionUtils.isEmpty(boardConfigLists)) {
            addressNumList = boardConfigLists.stream().map(BoardConfig::getAddress).distinct().toList();
        }

        log.info("查询所有板子地址 time:{}ms-{}", System.currentTimeMillis() - startTime, addressNumList);
        if (CollectionUtils.isEmpty(addressNumList)) {
            return Collections.emptyList();
        }

        var operationDetailListAll = operationDetailMapper.findDetailNotSingleByList(cabinetNo, addressNumList);
        var operationDetailListTwoAll = operationDetailMapper.findDetailSingleAndFinishOrInterruptByList(cabinetNo, addressNumList);
        var operationDetailListThreeAll = operationDetailMapper.findDetailSingleAndTimeoutByList(nowTime, cabinetNo, addressNumList);

        Map<Integer, List<OperationDetail>> mapAll = operationDetailListAll.stream()
                .collect(Collectors.groupingBy(OperationDetail::getBoardAddress));
        Map<Integer, List<OperationDetail>> mapTwoAll = operationDetailListTwoAll.stream()
                .collect(Collectors.groupingBy(OperationDetail::getBoardAddress));
        Map<Integer, List<OperationDetail>> mapThreeAll = operationDetailListThreeAll.stream()
                .collect(Collectors.groupingBy(OperationDetail::getBoardAddress));


        // 使用 merge 方法合并
        mapTwoAll.forEach((key, value) -> mapAll.merge(key, value, (oldList, newList) -> {
            if (!CollectionUtils.isEmpty(newList)) {
                oldList.addAll(newList);
            }
            return oldList;
        }));

        // 使用 merge 方法合并
        mapThreeAll.forEach((key, value) -> mapAll.merge(key, value, (oldList, newList) -> {
            if (!CollectionUtils.isEmpty(newList)) {
                oldList.addAll(newList);
            }
            return oldList;
        }));

        for (var address : mapAll.keySet()) {
            boolean isHasBattery = false;
            var operationDetailList = mapAll.get(address);
            if (!firstCommand) {
                // 剔除异常状态
                isHasBattery = !CollectionUtils.isEmpty(operationDetailList);
                operationDetailList.removeIf(o -> ServerConstant.START_FLAG_ERROR == o.getStartFlag());
                if (!command.isSingleChannel()) {
                    operationDetailList.removeIf(o -> ServerConstant.SINGLE_TYPE_SINGLE == o.getSingleType());
                }
                //log.info("剔除异常状态后address:{},boardAddressList:{}", address, gson.toJson(operationDetailList));
            }

            var commandBoardInfo = new CommandBoardInfo();
            commandBoardInfo.setSingleChannel(false);
            commandBoardInfo.setBoardAddress(address);
            commandBoardInfo.setOrderNo(command.getOrder());
            commandBoardInfo.setStepId(command.getStepId());
            commandBoardInfo.setCells(getCellNum(operationDetailList, isHasBattery));
            commandBoardInfos.add(commandBoardInfo);
        }


        log.info("查询所有板子操作 time:{}ms-{}", System.currentTimeMillis() - startTime, commandBoardInfos.size());
//        for (var address : addressNumList) {
//            boolean isHasBattery = false;
//            var operationDetailList = operationDetailMapper.findDetailNotSingle(cabinetNo, address);
//            if (!firstCommand) {
//                // 剔除异常状态
//                isHasBattery = !CollectionUtils.isEmpty(operationDetailList);
//                operationDetailList.removeIf(o -> ServerConstant.START_FLAG_ERROR == o.getStartFlag());
//                //log.info("剔除异常状态后address:{},boardAddressList:{}", address, gson.toJson(operationDetailList));
//            }
//            // 第一次下发
//            if (NumConstant.INT_ONE == command.getOrder()) {
//                var operationDetailListTwo = operationDetailMapper.findDetailSingleAndFinishOrInterrupt(cabinetNo, address);
//                var operationDetailListThree = operationDetailMapper.findDetailSingleAndTimeout(cabinetNo, address, nowTime);
//                if (!CollectionUtils.isEmpty(operationDetailListTwo)) {
//                    operationDetailList.addAll(operationDetailListTwo);
//                }
//                if (!CollectionUtils.isEmpty(operationDetailListThree)) {
//                    operationDetailList.addAll(operationDetailListThree);
//                }
//            }
//            var commandBoardInfo = new CommandBoardInfo();
//            commandBoardInfo.setSingleChannel(false);
//            commandBoardInfo.setBoardAddress(address);
//            commandBoardInfo.setOrderNo(command.getOrder());
//            commandBoardInfo.setStepId(command.getStepId());
//            commandBoardInfo.setCells(getCellNum(operationDetailList, isHasBattery));
//            commandBoardInfos.add(commandBoardInfo);
//        }


//
//        for (var address : addressNumList) {
//            boolean isHasBattery = false;
//            var operationDetailList = operationDetailMapper.findDetailNotSingle(cabinetNo, address);
//            if (!firstCommand) {
//                // 剔除异常状态
//                isHasBattery = !CollectionUtils.isEmpty(operationDetailList);
//                operationDetailList.removeIf(o -> ServerConstant.START_FLAG_ERROR == o.getStartFlag());
//                //log.info("剔除异常状态后address:{},boardAddressList:{}", address, gson.toJson(operationDetailList));
//            }
//            // 第一次下发
//            if (NumConstant.INT_ONE == command.getOrder()) {
//                var operationDetailListTwo = operationDetailMapper.findDetailSingleAndFinishOrInterrupt(cabinetNo, address);
//                var operationDetailListThree = operationDetailMapper.findDetailSingleAndTimeout(cabinetNo, address, nowTime);
//                if (!CollectionUtils.isEmpty(operationDetailListTwo)) {
//                    operationDetailList.addAll(operationDetailListTwo);
//                }
//                if (!CollectionUtils.isEmpty(operationDetailListThree)) {
//                    operationDetailList.addAll(operationDetailListThree);
//                }
//            }
//            var commandBoardInfo = new CommandBoardInfo();
//            commandBoardInfo.setSingleChannel(false);
//            commandBoardInfo.setBoardAddress(address);
//            commandBoardInfo.setOrderNo(command.getOrder());
//            commandBoardInfo.setStepId(command.getStepId());
//            commandBoardInfo.setCells(getCellNum(operationDetailList, isHasBattery));
//            commandBoardInfos.add(commandBoardInfo);
//        }

        log.info("获取getCommandBoardInfo time:{}ms", System.currentTimeMillis() - startTime);

        commandBoardInfos.removeIf(o -> null != o && CollectionUtils.isEmpty(o.getCells()));
        return commandBoardInfos;
    }


    private List<CommandBoardInfo> getSingleCommandBoardInfo(CommandIssuedSuccess command, boolean firstCommand) {

        // 单个通道指令下发，通道所在板子地址
        var lineNo = command.getBoardNo() + NumConstant.INT_ONE;
        var boardAddressList = boardConfigMapper.queryByDoorChannelLineNum(command.getDoor(), command.getChannelNo(), lineNo);
        Assert.notEmpty(boardAddressList, String.format("CommandIssuedSuccess boardAddressList is empty, door: %s, channelNo: %s, lineNo: %s", command.getDoor(), command.getChannelNo(), lineNo));

        var boardAddress = boardAddressList.getFirst();

        if (!firstCommand) {
            // 查询是否是异常状态
            var op = operationDetailMapper.findOneDetailByCellNum(command.getReqCabinetNo(), boardAddress, command.getChannelNo());
            if (null != op && ServerConstant.START_FLAG_ERROR == op.getStartFlag()) {
                return Collections.emptyList();
            }
        }

        var commandBoardInfo = new CommandBoardInfo();
        commandBoardInfo.setSingleChannel(true);
        commandBoardInfo.setStepId(command.getStepId());
        commandBoardInfo.setOrderNo(command.getOrder());
        commandBoardInfo.setBoardAddress(boardAddress);
        commandBoardInfo.setCells(Collections.singletonList(command.getChannelNo()));
        List<CommandBoardInfo> commandBoardInfoList = new ArrayList<>();
        commandBoardInfoList.add(commandBoardInfo);
        return commandBoardInfoList;
    }

    private List<Integer> getCellNum(List<OperationDetail> operationDetailList, boolean isHasBattery) {
        if (operationDetailList.isEmpty() && !isHasBattery) {
            List<Integer> cellNumList = new ArrayList<>();
            cellNumList.add(NumConstant.INT_ONE);
            cellNumList.add(NumConstant.INT_TWO);
            cellNumList.add(NumConstant.INT_THREE);
            cellNumList.add(NumConstant.INT_FOUR);
            cellNumList.add(NumConstant.INT_FIVE);
            cellNumList.add(NumConstant.INT_SIX);
            cellNumList.add(NumConstant.INT_SEVEN);
            cellNumList.add(NumConstant.INT_EIGHT);
            return cellNumList;
        }

        operationDetailList.sort(Comparator.comparing(OperationDetail::getCellNum));
        return operationDetailList.stream().map(OperationDetail::getCellNum).distinct().toList();
    }

    private CommandOutInfo getCommandOutInfo(CommandBoardOutInfo c) {
        var cellNum = NumConstant.INT_ZERO;
        var boardNum = NumConstant.INT_ZERO;
        for (var cell : c.getCells()) {
            cellNum += (int) Math.pow(NumConstant.INT_TWO, cell - NumConstant.INT_ONE);
        }
        for (var board : c.getBoardAddress()) {
            boardNum += (int) Math.pow(NumConstant.INT_TWO, board);
        }

        var commandOutInfo = new CommandOutInfo();
        commandOutInfo.setStepId(c.getStepId());
        commandOutInfo.setBoardNoNumber(boardNum);
        commandOutInfo.setCellsNoNumber(cellNum);
        commandOutInfo.setSingleChannel(c.getSingleChannel());
        commandOutInfo.setBoardAddress(c.getBoardAddress());
        commandOutInfo.setCells(c.getCells());
        return commandOutInfo;
    }
}
